
from block import Block
from device import BlockDevice
from utility import BitUtility, Bit
class Page(object):
    F_DIRTY    = Bit(0)
    F_UPTODATE = Bit(1)
    def __init__(self, bdev: BlockDevice | None = None, index: int = 0, size: int = 4096):
        size = Page.__checked_align(size) 
        if bdev is not None and bdev.block_size() > size:
            size = bdev.block_size()

        self.__index = index

        self.__block = Block.from_size(size)
        self.__bdev = bdev
        self.__flag = 0


    def bdev(self) -> BlockDevice:
        return self.__bdev

    def set_bdev(self, bdev: BlockDevice) -> bool:
        if bdev is not None and bdev.block_size() <= self.size():
            self.__bdev = bdev
            return True
        else:
            return False
    def index(self) -> int:
        return self.__index

    def size(self) -> int:
        return self.__block.size()

    def data(self) -> bytearray:
        return self.__block.data()


    def is_uptodate(self) -> bool:
        return Page.F_UPTODATE.is_set(self.__flag)
    def update(self) -> bool:
        if self.__bdev is None:
            return False
        #TODO: 
        self.__flag = Page.F_UPTODATE.set(self.__flag)
        return True


    def is_dirty(self) -> bool:
        return Page.F_DIRTY.is_set(self.__flag)
    def mark_dirty(self) -> bool:
        if self.__bdev is None:
            return False
        #TODO:
        self.__flag = Page.F_DIRTY.set(self.__flag)
        return True

    

    def sync(self) -> bool:  
        print("TODO: sync the page:{self}")
        if self.is_dirty():
            #TODO:
            pass
        return True

    @staticmethod
    def __checked_align(size: int) -> int:
        return BitUtility.align_greater_equal(size, 4096)

    def __repr__(self):
        return "Page=>key:[{}]+[{}]-flag:[{},Dirty:0x01,Uptodate:0x02]".format(self.__bdev.name(), self.__index, self.__flag)

import unittest
from device import MockFloppyDiskDriver
class TestPage(unittest.TestCase):
    def test_main(self):
        bdev = MockFloppyDiskDriver()

        page = Page(bdev)
        sz = page.size()
        self.assertEqual(4096, sz)

        self.assertFalse(page.is_uptodate())
        self.assertTrue(page.update())
        self.assertTrue(page.is_uptodate())

        self.assertFalse(page.is_dirty())
        self.assertTrue(page.mark_dirty())
        self.assertTrue(page.is_dirty())
